﻿using System.Text;
using System;
using SkiaSharp;

namespace FileStorage.Common
{
    public static class CaptchaHelper
    {
        /// <summary>
        /// 获取验证问题：Tuple第一个值是表达式，第二个值是表达式结果
        /// </summary>
        /// <returns></returns>
        public static Tuple<string, int> GetCaptchaQuestion()
        {
            var objRandom = new Random();
            var operArray = new string[] { "+", "*", "-", "/" };
            var left = objRandom.Next(0, 10);
            var right = objRandom.Next(0, 10);
            var oper = operArray[objRandom.Next(0, operArray.Length)];
            string key;
            int val;
            switch (oper)
            {
                default:
                case "+":
                    key = string.Format("{0}+{1}=?", left, right);
                    val = left + right;
                    break;
                case "*":
                    key = string.Format("{0}*{1}=?", left, right);
                    val = left * right;
                    break;
                case "-":
                    if (left < right)
                    {
                        (right, left) = (left, right);
                    }
                    key = string.Format("{0}-{1}=?", left, right);
                    val = left - right;
                    break;
                    //case "/":
                    //    right = objRandom.Next(1, 10);
                    //    left = right * objRandom.Next(1, 10);
                    //    key = string.Format("{0}÷{1}=?", left, right);
                    //    val = left / right;
                    //    break;
            }
            return new Tuple<string, int>(key, val);
        }

        /// <summary>
        /// 获取验证码
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <param name="addUpperLetter">加入大写字母A-Z，不包括O</param>
        /// <param name="addLowerLetter">加入小写字母a-z，不包括o</param>
        /// <returns></returns>
        public static string GetCaptchaCode(int length = 4, bool addUpperLetter = true, bool addLowerLetter = true)
        {
            var objStringBuilder = new StringBuilder();

            //加入数字1-9，不包括 1
            for (int i = 1; i <= 9; i++)
            {
                if(i != 1)
                {
                    objStringBuilder.Append(i);
                }
            }

            //加入大写字母A-Z，不包括 I,L,O
            if (addUpperLetter)
            {
                for (int i = 0; i < 26; i++)
                {
                    char temp = Convert.ToChar(i + 65);
                    if (!temp.Equals('I') && !temp.Equals('L') && !temp.Equals('O'))
                    {
                        objStringBuilder.Append(temp);
                    }
                }
            }

            //加入小写字母a-z，不包括 i,l,o
            if (addLowerLetter)
            {
                for (int i = 0; i < 26; i++)
                {
                    char temp = Convert.ToChar(i + 97);
                    if (!temp.Equals('i') && !temp.Equals('l') && !temp.Equals('o'))
                    {
                        objStringBuilder.Append(temp);
                    }
                }
            }

            //生成验证码字符串
            var result = "";
            var objRandom = new Random();
            for (int i = 0; i < length; i++)
            {
                int index = objRandom.Next(0, objStringBuilder.Length);
                result += objStringBuilder[index];
                objStringBuilder.Remove(index, 1);
            }

            return result;
        }

        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="captchaCodeText">验证码文本</param>
        /// <param name="setRandomColor">是否随机字体颜色</param>
        /// <returns></returns>
        public static byte[] CreateCaptchaImage(string captchaCodeText, bool setRandomColor = true)
        {
            const int fontSize = 36;  // 字体大小
            const int randAngle = 30; // 随机码的旋转角度
            string[] fontFamilies = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "宋体" }; // 字体类型
            var fontColor = SKColors.Blue; // 字体颜色

            int mapWidth = captchaCodeText.Length * (fontSize + 2);  // 图片宽度
            int mapHeight = Convert.ToInt32((60.0 / 100) * fontSize + fontSize); // 图片高度

            var objRandom = new Random();

            //创建bitmap位图
            using var map = new SKBitmap(mapWidth, mapHeight, SKColorType.Bgra8888, SKAlphaType.Premul);
            //创建画笔
            using var canvas = new SKCanvas(map);

            //填充白色背景
            canvas.Clear(SKColors.AliceBlue);

            //添加前景噪点
            AddForeNoisePoint(map, objRandom);
            //添加背景噪点
            AddBackgroundNoisePoint(map, canvas, objRandom);

            //canvas.DrawColor(SKColors.White);

            //将文字写到画布上
            int fontIndex = objRandom.Next(fontFamilies.Length);
            var drawStyle = new SKPaint
            {
                IsAntialias = true,
                TextSize = fontSize,
                Typeface = SKTypeface.FromFamilyName(fontFamilies[fontIndex], SKFontStyleWeight.SemiBold, SKFontStyleWidth.ExtraCondensed, SKFontStyleSlant.Upright)
            };
            char[] chars = captchaCodeText.ToCharArray();
            for (int i = 0; i < chars.Length; i++)
            {
                //转动的度数
                float angle = objRandom.Next(-randAngle, randAngle);
                canvas.Translate(12, 12);

                float px = ((i) * fontSize);
                if (i == 0)
                    px += 3;
                if (i == chars.Length - 1)
                    px -= 3;
                float py = (mapHeight) / 2;
                canvas.RotateDegrees(angle, px, py);

                // int fontIndex = objRandom.Next(fontFamilies.Length);
                // var face = SKTypeface.FromFamilyName(fontFamilies[fontIndex], SKFontStyleWeight.SemiBold, SKFontStyleWidth.ExtraCondensed, SKFontStyleSlant.Upright);
                // drawStyle.Typeface = face;
                drawStyle.Color = setRandomColor ? GetRandomColor() : fontColor;
                //写字 (i + 1) * 16, 28
                // canvas.DrawText(chars[i].ToString(), (i) * fontSize, (mapHeight-1), drawStyle);
                canvas.DrawText(chars[i].ToString(), px, py, drawStyle);

                canvas.RotateDegrees(-angle, px, py);
                canvas.Translate(-12, -12);
            }
            //绘制干扰曲线
            using (var disturbStyle = new SKPaint())
            {
                var random = new Random();
                for (int i = 0; i < 2; i++)
                {
                    disturbStyle.Color = SKColors.Gray;
                    disturbStyle.StrokeWidth = 1;
                    canvas.DrawLine(random.Next(0, mapWidth), random.Next(0, mapHeight), random.Next(0, mapWidth), random.Next(0, mapHeight), disturbStyle);
                }
            }

            //返回图片byte
            using SKImage img = SKImage.FromBitmap(map);
            using SKData p = img.Encode(SKEncodedImageFormat.Png, 100);
            return p.ToArray();
        }


        #region Private Method

        /// <summary>
        /// 获取随机颜色
        /// </summary>
        /// <returns></returns>
        private static SKColor GetRandomColor()
        {
            //var RandomNum_First = new Random((int)DateTime.Now.Ticks);
            //// 对于C#的随机数，没什么好说的
            //System.Threading.Thread.Sleep(RandomNum_First.Next(50));
            //var RandomNum_Sencond = new Random((int)DateTime.Now.Ticks);
            //// 为了在白色背景上显示，尽量生成深色
            //int int_Red = RandomNum_First.Next(256);
            //int int_Green = RandomNum_Sencond.Next(256);
            //int int_Blue = (int_Red + int_Green > 400) ? 0 : 400 - int_Red - int_Green;
            //int_Blue = (int_Blue > 255) ? 255 : int_Blue;
            //return SKColor.FromHsv(int_Red, int_Green, int_Blue);

            var random = new Random();
            SKColor[] colors = { SKColors.Black, SKColors.Red, SKColors.DarkBlue, SKColors.Green, SKColors.Orange, SKColors.Brown, SKColors.DarkCyan, SKColors.Purple };
            int cindex = random.Next(colors.Length);
            return colors[cindex];
        }

        /// <summary>
        /// 创建画笔
        /// </summary>
        /// <param name="color"></param>
        /// <param name="fontSize"></param>
        /// <returns></returns>
        private static SKPaint CreatePaint(SKColor color, float fontSize)
        {
            SKTypeface font = SKTypeface.FromFamilyName(null, SKFontStyleWeight.SemiBold, SKFontStyleWidth.ExtraCondensed, SKFontStyleSlant.Upright);
            var paint = new SKPaint
            {
                IsAntialias = true,
                Color = color,
                Typeface = font,
                TextSize = fontSize
            };
            return paint;
        }

        /// <summary>
        /// 前景噪点
        /// </summary>
        /// <param name="objBitmap"></param>
        /// <param name="objRandom"></param>
        /// <param name="foreNoisePointCount">前景噪点数量</param>
        private static void AddForeNoisePoint(SKBitmap objBitmap, Random objRandom, int foreNoisePointCount = 2)
        {
            for (int i = 0; i < objBitmap.Width * foreNoisePointCount; i++)
            {
                objBitmap.SetPixel(objRandom.Next(objBitmap.Width), objRandom.Next(objBitmap.Height), SKColors.Gray);
            }
        }

        /// <summary>
        /// 背景噪点
        /// </summary>
        /// <param name="objBitmap"></param>
        /// <param name="objCanvas"></param>
        /// <param name="objRandom"></param>
        /// <param name="setBackgroundLine">是否加入背景线</param>
        private static void AddBackgroundNoisePoint(SKBitmap objBitmap, SKCanvas objCanvas, Random objRandom, bool setBackgroundLine = false)
        {
            using (SKPaint objPen = CreatePaint(SKColors.Azure, 0))
            {
                for (int i = 0; i < objBitmap.Width * 2; i++)
                {
                    //objGraphics.DrawRectangle(objPen, objRandom.Next(objBitmap.Width), objRandom.Next(objBitmap.Height), 1, 1);
                    objCanvas.DrawRect(objRandom.Next(objBitmap.Width), objRandom.Next(objBitmap.Height), 1, 1, objPen);
                }
            }

            if (setBackgroundLine)
            {
                //画图片的背景噪音线
                for (var i = 0; i < 12; i++)
                {
                    var x1 = objRandom.Next(objBitmap.Width);
                    var x2 = objRandom.Next(objBitmap.Width);
                    var y1 = objRandom.Next(objBitmap.Height);
                    var y2 = objRandom.Next(objBitmap.Height);

                    objCanvas.DrawLine(x1, y1, x2, y2, CreatePaint(SKColors.Silver, 0));
                }
            }
        }

        #endregion
    }
}
